﻿#if (WINDOWS_PHONE == false) && (SILVERLIGHT == true)

using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Reactive.Linq;
using Polenter.Serialization;
using SoTools.Communicator.Messages;

namespace SoTools.Communicator
{
    public sealed partial class Communicator
    {
        private bool _joined = false;
        private UdpAnySourceMulticastClient _client = null;

        public void Publish(BaseMessage message)
        {
            if (!_joined)
                return;

            using (var ms = new MemoryStream())
            {
                var serializer = new SharpSerializer(true);
                serializer.Serialize(message, ms);

                ms.Flush();
                ms.Position = 0;
                var buffer = new byte[ms.Length];
                ms.Read(buffer, 0, buffer.Length);

                _client.BeginSendToGroup(buffer, 0, buffer.Length, _client.EndSendToGroup, null);
            }
        }

        public IObservable<T> GenerateObservable<T>() where T : BaseMessage
        {
            return Observable.FromEventPattern<BaseMessageEventArgs>(h => OnMessageReceived += h, h => OnMessageReceived -= h)
                .Where(args => args.EventArgs.Message is T)
                .Select(args => args.EventArgs.Message as T);
        }

        public void Listen()
        {
            if (_networkObserver != null)
                return;

            if (_client != null)
                _client.Dispose();

            _joined = false;

            _client = new UdpAnySourceMulticastClient(_multicastAddress, _multicastPort);

            var buffer = new byte[10240];
            _networkObserverFactory = Observable.FromAsyncPattern((callback, obj) => _client.BeginReceiveFromGroup(buffer, 0, buffer.Length, callback, obj),
                                                                  r =>
                                                                  {
                                                                      IPEndPoint endpoint;
                                                                      var size = _client.EndReceiveFromGroup(r, out endpoint);
                                                                      var result = new byte[size];
                                                                      Array.Copy(buffer, result, size);
                                                                      return result;
                                                                  });

            _client.BeginJoinGroup(result =>
            {
                _client.EndJoinGroup(result);

                // Multicast successfully joined !
                _joined = true;

                // We don't want to receive the messages we send.
                _client.MulticastLoopback = true;

                _networkObserver = _networkObserverFactory.Invoke().Subscribe(OnReceive);
            },
                                    null);
        }
    }
}

#endif